package com.yuandian.middle.platform.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuandian.api.management.entity.ConfMpService;
import com.yuandian.api.middle_platform.po.HttpResultVo;
import com.yuandian.api.middle_platform.po.IndicatorReportingParam;
import com.yuandian.api.middle_platform.vo.ImplementationIndicatorVo;
import com.yuandian.api.middle_platform.vo.OperationalIndicatorResultVo;
import com.yuandian.api.middle_platform.vo.OperationalIndicatorVo;
import com.yuandian.bpm.admin.api.feign.RemoteParamService;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.constant.ConfigKey;
import com.yuandian.enums.MajorDimensionEnum;
import com.yuandian.enums.SubDimensionEnum;
import com.yuandian.middle.platform.enums.IndexTypeEnum;
import com.yuandian.middle.platform.mapper.IndicatorReportingMapper;
import com.yuandian.middle.platform.service.IIndicatorReportingService;
import com.yuandian.middle.platform.utils.HttpUtil;
import com.yuandian.middle.platform.utils.SFTPUtils;
import com.yuandian.middle.platform.utils.SheetHeadUtil;
import com.yuandian.middle.platform.utils.TextFileGenerator;
import com.yuandian.utils.BeanUtils;
import com.yuandian.utils.PageDataInfo;
import com.yuandian.utils.StringUtils;
import com.yuandian.utils.poi.ExcelUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * 说明：指标上报(中台二期)
 * @Author LSH
 * @Date 2023/5/23 14:10
 */
@Service
@Slf4j

public class IndicatorReportingServiceImpl implements IIndicatorReportingService {

	/**
	 * 当前应用程序，启动目录
	 */
	private static final String user_path = "user.dir";

	/**
	 * 文档生成存放路径名称
	 */
	private static final String doc_path = "docs";

	/**
	 *  文档生成存放基础路径
	 */
	private  static final String SFTP_DOWN_PATH =  System.getProperty(user_path)+File.separator+doc_path;

    @Autowired
    private IndicatorReportingMapper reportingMapper;

	@Autowired
	private RemoteParamService remoteParamService;

	@Autowired
	private SFTPUtils sftpUtils;


	/** '请求量 量纲 字段前缀'*/
	private static final String REQUEST_FIELD = "A";
	/** '请求失败量-自身原因 量纲 字段前缀'*/
	private static final String FAIL_SELF_REQUEST_FIELD = "B";
	/** '请求失败量-非自身原因 量纲 字段前缀'*/
	private static final String FAIL_OTHER_REQUEST_FIELD = "C";


	private static final String ZLG = "ZLG";
	private static final String FLG = "FLG";
	private static final String ZSYY = "ZSYY";
	private static final String FZSYY = "FZSYY";

	/** 指标创建标志，表示是否向agent创建了相关的指标 */
	private static boolean API_INDEX_CREATE_FLAG = false;
	private static boolean SDK_INDEX_CREATE_FLAG = false;
	private static boolean H5_INDEX_CREATE_FLAG = false;
	private static boolean PAAS_SAAS_INDEX_CREATE_FLAG = false;


	/**
	 * 查询运营指标
	 * @param param	请求参数
	 * @return	通用结果集
	 */
    @Override
    public R<OperationalIndicatorResultVo> queryOperationalIndicators(IndicatorReportingParam param) {
		Page page = new Page<>(param.getPageNum(), param.getPageSize());
		Map<String, Map<String, Object>> businessDataMap = new LinkedHashMap<>();

		// 保存前端列表表头字段集
		Map<String, Object> fieldMap = new LinkedHashMap<>();
		Map<String, Object> filedReqFailCountMap = new LinkedHashMap<>();

		// 1.根据服务编码获取服务 主量纲 和 副量纲
		ConfMpService confMpService = reportingMapper.queryServiceInfo(param);
		if (confMpService == null || StringUtils.isBlank(confMpService.getMajorDimension())) { return R.failed("找不到该服务对应主量纲"); }

		String majorDimension = confMpService.getMajorDimension();
		String subDimensionStr = confMpService.getSubDimension();

//		String majorDimension = "xtywl";
//		String subDimensionStr = "yhsyl,zhktl";
		List<String> subDimensionList = StringUtils.isNotEmpty(subDimensionStr) ? Arrays.asList(subDimensionStr.split(",")) : null;


		// 2.查询 主量纲 信息
		List<OperationalIndicatorVo> majorDimensionDataVoList = getDimension(param, majorDimension);
		if (CollectionUtil.isNotEmpty(majorDimensionDataVoList)) {
			for (OperationalIndicatorVo vo : majorDimensionDataVoList) {
				Map<String, Object> map = new LinkedHashMap<>();							// 每行数据的总结果集
				Map<String, Object> reqCountMap = new LinkedHashMap<>();					// 调用量结果集
				Map<String, Map<String, Object>> reqFailCountMap = new LinkedHashMap<>();	// 调用失败量结果集
				Map<String, Object> reqFailSelfReasonsMap = new LinkedHashMap<>();			// 调用失败自身原因结果集
				Map<String, Object> reqFailOtherReasonsMap = new LinkedHashMap<>();			// 调用失败非自身原因结果集


//					String resultKey = vo.getCycleTime() + vo.getAbilityName() + vo.getServiceName() + vo.getUserOrgName();
				String resultKey = vo.getCycleTime() + vo.getAbilityName() + vo.getUserOrgName();  // 用来关联 主、副 量纲

				// 封装 通用字段数据
				map.put("cycleTime", vo.getCycleTime());
				map.put("abilityCode", vo.getAbilityCode());
				map.put("abilityName", vo.getAbilityName());
				map.put("serviceCode", vo.getServiceCode());
				map.put("serviceName", vo.getServiceName());
				map.put("orgCode", vo.getOrgCode());
				map.put("orgName", vo.getOrgName());
				map.put("userOrgCode", vo.getUserOrgCode());
				map.put("userOrgName", vo.getUserOrgName());
				map.put("appCode", vo.getAppCode());
				map.put("appName", vo.getAppName());
				map.put("departmentCode", vo.getDepartmentCode());
				map.put("departmentName", vo.getDepartmentName());
				map.put("orderCode", vo.getOrderCode());
				map.put("suborderCode", vo.getSuborderCode());
				// 封装调用量字段数据
				reqCountMap.put(majorDimension+"_"+REQUEST_FIELD+"1", vo.getReqCount());
				// 封装失败调用量字段数据
				reqFailSelfReasonsMap.put(majorDimension+"_"+FAIL_SELF_REQUEST_FIELD+"1", vo.getSelfReasonsFailCount());
				reqFailOtherReasonsMap.put(majorDimension+"_"+FAIL_OTHER_REQUEST_FIELD+"1", vo.getOtherReasonsFailCount());

				reqFailCountMap.put("reqFailSelfReasons", reqFailSelfReasonsMap);
				reqFailCountMap.put("reqFailOtherReasonsMap", reqFailOtherReasonsMap);
				map.put("reqCountMap", reqCountMap);
				map.put("reqFailCountMap", reqFailCountMap);

				Map<String, Object> childMap = ObjectUtil.clone(map);
				businessDataMap.put(resultKey, childMap);
			}
		}


		// 3.封装列表表头中英文字段给前端
		fieldMap.put("cycleTime", "数据时间");
		fieldMap.put("abilityName", "能力名称");
		fieldMap.put("serviceName", "服务名称");
		fieldMap.put("userOrgName", "使用方名称");

		List<Object> filedReqCountList = new ArrayList<>();
		Map<String, Object> majorDimensionReqCountMap = new LinkedHashMap<>();
		majorDimensionReqCountMap.put("value", majorDimension + "_" + REQUEST_FIELD + "1");
		majorDimensionReqCountMap.put("label", MajorDimensionEnum.getMsgByCode(majorDimension) + "（主）");
		filedReqCountList.add(majorDimensionReqCountMap);
		fieldMap.put("filedReqCountMap", filedReqCountList);

		List<Object> filedReqFailSelfReasonsList = new ArrayList<>();
		Map<String, Object> majorDimensionFailSelfCountMap = new LinkedHashMap<>();
		majorDimensionFailSelfCountMap.put("value", majorDimension + "_" + FAIL_SELF_REQUEST_FIELD + "1");
		majorDimensionFailSelfCountMap.put("label", MajorDimensionEnum.getMsgByCode(majorDimension) + "（主）");
		filedReqFailSelfReasonsList.add(majorDimensionFailSelfCountMap);
		filedReqFailCountMap.put("filedReqFailSelfReasons", filedReqFailSelfReasonsList);

		List<Object> filedReqFailOtherReasonsList = new ArrayList<>();
		Map<String, Object> majorDimensionFailOtherCountMap = new LinkedHashMap<>();
		majorDimensionFailOtherCountMap.put("value", majorDimension + "_" + FAIL_OTHER_REQUEST_FIELD + "1");
		majorDimensionFailOtherCountMap.put("label", MajorDimensionEnum.getMsgByCode(majorDimension) + "（主）");
		filedReqFailOtherReasonsList.add(majorDimensionFailOtherCountMap);
		filedReqFailCountMap.put("filedReqFailOtherReasonsMap", filedReqFailOtherReasonsList);

		fieldMap.put("filedReqFailCountMap", filedReqFailCountMap);


		// 4.查询 副量纲信息
		if (!CollectionUtils.isEmpty(subDimensionList)) {
			int index = 2;
			Set<Map.Entry<String, Map<String, Object>>> entries = businessDataMap.entrySet();

			// 遍历 副量纲 列表，挨个查询对应数据，并整合到 主量纲 列表里
			for (String subDimension : subDimensionList) {
				// 查询指定 副量纲 对应数据，并整合到 主量纲 集合里面
				List<OperationalIndicatorVo> subDimensionEnumDataVoList = getDimension(param, subDimension);
				for (Map.Entry<String, Map<String, Object>> entry : entries) {
					boolean flag = false;
					String key = entry.getKey();
					Map<String, Object> map = entry.getValue();
					// 获取调用量结果集并回填 调用量 副量纲 的字段值 key => A + index
					Map<String, Object> reqCountMap = (LinkedHashMap<String, Object>) map.get("reqCountMap");

					// 回填调用 调用失败量 -> 自身原因和非自身原因 的 副量纲 调用量
					Map<String, Map<String, Object>> reqFailCountMap = (LinkedHashMap<String, Map<String, Object>>) map.get("reqFailCountMap");
					Map<String, Object> reqFailSelfReasonsMap = reqFailCountMap.get("reqFailSelfReasons");
					Map<String, Object> reqFailOtherReasonsMap = reqFailCountMap.get("reqFailOtherReasonsMap");

					for (OperationalIndicatorVo vo : subDimensionEnumDataVoList) {
//							String resultKey = vo.getCycleTime() + vo.getAbilityName() + vo.getServiceName() + vo.getUserOrgName();
						String resultKey = vo.getCycleTime() + vo.getAbilityName() + vo.getUserOrgName();
						if (key.equalsIgnoreCase(resultKey)) {
							flag = true;
							reqCountMap.put(subDimension+"_"+REQUEST_FIELD+index, vo.getReqCount());	// 调用量 -> 副量纲
							reqFailSelfReasonsMap.put(subDimension+"_"+FAIL_SELF_REQUEST_FIELD+index, vo.getSelfReasonsFailCount());		// 调用失败量 -> 自身原因 -> 副量纲
							reqFailOtherReasonsMap.put(subDimension+"_"+FAIL_OTHER_REQUEST_FIELD+index, vo.getOtherReasonsFailCount());	// 调用失败量 -> 非自身原因 -> 副量纲
							break;
						}
					}

					// 如果 副量纲 里面找不到对应 key 的数据则进行补0
					if (!flag) {
						reqCountMap.put(subDimension+"_"+REQUEST_FIELD+index, 0);
						reqFailSelfReasonsMap.put(subDimension+"_"+FAIL_SELF_REQUEST_FIELD+index, 0);
						reqFailOtherReasonsMap.put(subDimension+"_"+FAIL_OTHER_REQUEST_FIELD+index, 0);
					}
				}

				// 5.封装列表表头中英文字段给前端
				filedReqFailCountMap = (Map<String, Object>) fieldMap.get("filedReqFailCountMap");
				filedReqCountList = (List<Object>) fieldMap.get("filedReqCountMap");
				filedReqFailSelfReasonsList = (List<Object>) filedReqFailCountMap.get("filedReqFailSelfReasons");
				filedReqFailOtherReasonsList = (List<Object>) filedReqFailCountMap.get("filedReqFailOtherReasonsMap");

				majorDimensionReqCountMap = new LinkedHashMap<>();
				majorDimensionReqCountMap.put("value", subDimension + "_" + REQUEST_FIELD + index);
				majorDimensionReqCountMap.put("label",  SubDimensionEnum.getMsgByCode(subDimension) + "（副）");
				filedReqCountList.add(majorDimensionReqCountMap);

				majorDimensionFailSelfCountMap = new LinkedHashMap<>();
				majorDimensionFailSelfCountMap.put("value", subDimension + "_" + FAIL_SELF_REQUEST_FIELD + index);
				majorDimensionFailSelfCountMap.put("label", SubDimensionEnum.getMsgByCode(subDimension) + "（副）");
				filedReqFailSelfReasonsList.add(majorDimensionFailSelfCountMap);

				majorDimensionFailOtherCountMap = new LinkedHashMap<>();
				majorDimensionFailOtherCountMap.put("value", subDimension + "_" + FAIL_OTHER_REQUEST_FIELD + index);
				majorDimensionFailOtherCountMap.put("label", SubDimensionEnum.getMsgByCode(subDimension) + "（副）");
				filedReqFailOtherReasonsList.add(majorDimensionFailOtherCountMap);

				index++;
			}
		}

		// 6.封装数据对象, 如果是列表查询则需要手动分页返回到前端，下载则不用分页
		List<Object> list = new ArrayList<>(businessDataMap.values());
		if (param.getPageSize() != -1) {
			page.setTotal(list.size());
			list = (List<Object>) getResultListByPage(param, list);
		}

		OperationalIndicatorResultVo result = new OperationalIndicatorResultVo();
		result.setFieldMap(fieldMap);
		result.setPageDataInfo(new PageDataInfo(page, list));

        return R.ok(result);
    }

	/**
	 * 查询实时指标
	 * @param param	请求参数
	 * @return	通用结果集
	 */
	@Override
	public R<PageDataInfo> queryImplementationIndicators(IndicatorReportingParam param) {
		Page page = new Page<>(param.getPageNum(), param.getPageSize());

		// 查询 API 指标
		List<ImplementationIndicatorVo> apiIndicatorList = reportingMapper.queryApiIndicators(param);

		// 查询 SDK 指标
		List<ImplementationIndicatorVo> sdkIndicatorList = reportingMapper.querySdkIndicators(param);

		// 查询 H5 指标
		List<ImplementationIndicatorVo> h5IndicatorList = reportingMapper.queryH5Indicators(param);

		// 查询 Paas / Saas 指标
		List<ImplementationIndicatorVo> paasSaasIndicatorList = reportingMapper.queryPaasSaasIndicators(param);

		// 合并数据
		List<ImplementationIndicatorVo> resultList = new ArrayList<>();
		if (apiIndicatorList.size() > 0) { resultList.addAll(apiIndicatorList); }
		if (sdkIndicatorList.size() > 0) { resultList.addAll(sdkIndicatorList); }
		if (h5IndicatorList.size() > 0) { resultList.addAll(h5IndicatorList); }
		if (paasSaasIndicatorList.size() > 0) { resultList.addAll(paasSaasIndicatorList); }

		// 排序数据
		resultList.sort(Comparator.comparing(ImplementationIndicatorVo::getAbilityType)
				.thenComparing(ImplementationIndicatorVo::getCycleTime));

		// 数据分页
		if (param.getPageSize() != -1) {
			page.setTotal(resultList.size());
			resultList = (List<ImplementationIndicatorVo>) getResultListByPage(param, resultList);
		}

		return R.ok(new PageDataInfo(page, resultList));
	}


	/**
	 * 运营  指标-导出
	 * @param params	请求参数
	 */
	@Override
	public void queryOperationalDown(IndicatorReportingParam params, HttpServletResponse response) throws IOException {

		// 1.获取'运营'指标数据
		List<Object> list = new ArrayList<>();
		Map<String, Object> fieldMap = new LinkedHashMap<>();
		R<OperationalIndicatorResultVo> r = queryOperationalIndicators(params);	// 查询数据
		if (r != null && r.getData() != null && r.getData().getPageDataInfo() != null) {
			list = (List<Object>) r.getData().getPageDataInfo().getData();
			fieldMap = r.getData().getFieldMap();
		}


		// 3.处理数据: 对 '运营' 指标数据格式转化成 List<List<Object>> 格式，用于导出
		List<List<Object>> operationalList = SheetHeadUtil.formatOperationalData(list);

		// 4.获取 '运营' 各自Sheet的表头
		List<List<String>> operationalSheetHead = SheetHeadUtil.getOperationalSheetHead(fieldMap);

		// 5.数据导出
		ExcelWriter excelWriter = null;
		try {
			excelWriter = EasyExcel.write(response.getOutputStream())
					.registerWriteHandler(new SimpleColumnWidthStyleStrategy(25))
					.registerWriteHandler(new SimpleRowHeightStyleStrategy((short)30, (short)20))
					.build();

			// '运营'指标写入
			ExcelUtil.writeOnly(excelWriter, operationalList, operationalSheetHead, 1, "运营指标");

			// 返回文件流
			ExcelUtil.writeExcel("业务步骤信息表", response);
		} catch (Exception e) {
			log.error("运营/实时指标-导出异常： " + e.getMessage());
		} finally {
			if (excelWriter != null) {
				try {
					response.getOutputStream().flush();
					excelWriter.finish();
					response.getOutputStream().close();
				}catch (Exception e) {
					log.error("IO流关闭异常： " + e.getMessage());
				}
			}
		}
	}


	/**
	 * 实时 指标-导出
	 * @param params	请求参数
	 */
	@Override
	public void queryImplementationDown(IndicatorReportingParam params, HttpServletResponse response) throws IOException {
		// 2.获取'实时'指标数据
		List<ImplementationIndicatorVo> implementationResList = new ArrayList<>();
		R<PageDataInfo> implementationR = queryImplementationIndicators(params);	// 查询数据
		if (implementationR != null && implementationR.getData() != null) {
			implementationResList = BeanUtils.cast(implementationR.getData().getData());
		}

		// 3.处理数据: 对' '实时'指标数据格式转化成 List<List<Object>> 格式，用于导出
 		List<List<Object>> implementationList = SheetHeadUtil.formatImplementationData(implementationResList);

		// 4.获取'运营'、'实时'各自Sheet的表头
 		List<List<String>> implementationSheetHead = SheetHeadUtil.getImplementationSheetHead();

		// 5.数据导出
		ExcelWriter excelWriter = null;
		try {
			excelWriter = EasyExcel.write(response.getOutputStream())
					.registerWriteHandler(new SimpleColumnWidthStyleStrategy(25))
					.registerWriteHandler(new SimpleRowHeightStyleStrategy((short)30, (short)20))
					.build();

			// '实时'指标写入
			ExcelUtil.writeOnly(excelWriter, implementationList, implementationSheetHead, 1, "实时指标");

			// 返回文件流
			ExcelUtil.writeExcel("业务步骤信息表", response);
		} catch (Exception e) {
			log.error("运营/实时指标-导出异常： " + e.getMessage());
		} finally {
			if (excelWriter != null) {
				try {
					response.getOutputStream().flush();
					excelWriter.finish();
					response.getOutputStream().close();
				}catch (Exception e) {
					log.error("IO流关闭异常： " + e.getMessage());
				}
			}
		}
	}


	/**
	 * 实时指标 上报
	 * @param param	请求参数
	 */
	@Override
	public void implementationIndicators(IndicatorReportingParam param) throws Exception {

		// 查询 API 指标
		long startTime = System.currentTimeMillis();
		List<ImplementationIndicatorVo> apiIndicatorList = reportingMapper.queryApiIndicators(param);
		List<Map<String, Map<String, Object>>> apiMapList = new ArrayList<>();
		for (ImplementationIndicatorVo apiVo : apiIndicatorList) {
			Map<String, Map<String, Object>> apiMap = new LinkedHashMap<>();
			Map<String, Object> labelMap = new LinkedHashMap<>();   // 标签集
			Map<String, Object> indexMap = new LinkedHashMap<>();	// 指标集

			labelMap.put("api_code", apiVo.getServiceCode());
			labelMap.put("ability_code", apiVo.getAbilityCode());
			labelMap.put("scenario_code", apiVo.getScenarioCode());
			labelMap.put("rq_service_orgid", apiVo.getDepartmentCode());
			labelMap.put("rq_appid", apiVo.getAppCode());
			labelMap.put("ability_type", apiVo.getAbilityType());

			indexMap.put("rq_total", apiVo.getApiReqCount());
			indexMap.put("rq_sys_success_total", apiVo.getApiSystemSuccessCount());
			indexMap.put("rq_biz_success_total", apiVo.getApiBusinessSuccessCount());
			indexMap.put("rq_avg_resp_time", apiVo.getApiAvgServerResponseTime());

			apiMap.put("labelMap", labelMap);
			apiMap.put("indexMap", indexMap);

			apiMapList.add(apiMap);
		}
		log.info("实时指标-数据上报-查询API类型数据，耗时：{} MS，总数：{}", System.currentTimeMillis() - startTime, apiMapList.size());

		// 查询 SDK 指标
		List<ImplementationIndicatorVo> sdkIndicatorList = reportingMapper.querySdkIndicators(param);
		List<Map<String, Map<String, Object>>> sdkMapList = new ArrayList<>();
		for (ImplementationIndicatorVo sdkVo : sdkIndicatorList) {
			Map<String, Map<String, Object>> sdkMap = new LinkedHashMap<>();
			Map<String, Object> labelMap = new LinkedHashMap<>();   // 标签集
			Map<String, Object> indexMap = new LinkedHashMap<>();	// 指标集

			labelMap.put("api_code", sdkVo.getServiceCode());
			labelMap.put("ability_code", sdkVo.getAbilityCode());
			labelMap.put("scenario_code", sdkVo.getScenarioCode());
			labelMap.put("rq_service_orgid", sdkVo.getDepartmentCode());
			labelMap.put("rq_appid", sdkVo.getAppCode());
			labelMap.put("ability_type", sdkVo.getAbilityType());

			indexMap.put("sdk_total", sdkVo.getSdkReqCount());
			indexMap.put("sdk_success_total", sdkVo.getSdkSystemSuccessCount());
			indexMap.put("sdk_pv", 0);
			indexMap.put("sdk_uv", 0);
			indexMap.put("sdk_vv", 0);

			sdkMap.put("labelMap", labelMap);
			sdkMap.put("indexMap", indexMap);

			sdkMapList.add(sdkMap);
		}
		log.info("实时指标-数据上报-查询SDK类型数据，耗时：{} MS，总数：{}", System.currentTimeMillis() - startTime, sdkMapList.size());

		// 查询 H5 指标
		List<ImplementationIndicatorVo> h5IndicatorList = reportingMapper.queryH5Indicators(param);
		List<Map<String, Map<String, Object>>> h5MapList = new ArrayList<>();
		for (ImplementationIndicatorVo h5Vo : h5IndicatorList) {
			Map<String, Map<String, Object>> h5Map = new LinkedHashMap<>();
			Map<String, Object> labelMap = new LinkedHashMap<>();   // 标签集
			Map<String, Object> indexMap = new LinkedHashMap<>();	// 指标集

			labelMap.put("api_code", h5Vo.getServiceCode());
			labelMap.put("ability_code", h5Vo.getAbilityCode());
			labelMap.put("scenario_code", h5Vo.getScenarioCode());
			labelMap.put("rq_service_orgid", h5Vo.getDepartmentCode());
			labelMap.put("rq_appid", h5Vo.getAppCode());
			labelMap.put("ability_type", h5Vo.getAbilityType());

			indexMap.put("h5_pv", h5Vo.getH5ReqCount());
			indexMap.put("h5_uv", 0);
			indexMap.put("h5_vv", 0);
			indexMap.put("h5_avg_rq_time", h5Vo.getH5AvgServerResponseTime());

			h5Map.put("labelMap", labelMap);
			h5Map.put("indexMap", indexMap);

			h5MapList.add(h5Map);
		}
		log.info("实时指标-数据上报-查询H5类型数据，耗时：{} MS，总数：{}", System.currentTimeMillis() - startTime, h5MapList.size());

		// 查询 Paas / Saas 指标
		List<ImplementationIndicatorVo> paasSaasIndicatorList = reportingMapper.queryPaasSaasIndicators(param);
		List<Map<String, Map<String, Object>>> paasSaasMapList = new ArrayList<>();
		for (ImplementationIndicatorVo paasSaasVo : paasSaasIndicatorList) {
			Map<String, Map<String, Object>> paasSaasMap = new LinkedHashMap<>();
			Map<String, Object> labelMap = new LinkedHashMap<>();   // 标签集
			Map<String, Object> indexMap = new LinkedHashMap<>();	// 指标集

			labelMap.put("ability_code", paasSaasVo.getAbilityCode());
			labelMap.put("tenant_code", paasSaasVo.getUserOrgCode());
			labelMap.put("ability_type", paasSaasVo.getAbilityType());

			indexMap.put("user_login_total", paasSaasVo.getPaasSaasLoginCount());
			indexMap.put("ordered_tools_qty", 0);
			indexMap.put("tools_use_total", 0);
			indexMap.put("network_recieve_total", paasSaasVo.getPaasSaasReqCount());

			paasSaasMap.put("labelMap", labelMap);
			paasSaasMap.put("indexMap", indexMap);

			paasSaasMapList.add(paasSaasMap);
		}
		log.info("实时指标-数据上报-查询paasSaas类型数据，耗时：{} MS，总数：{}", System.currentTimeMillis() - startTime, paasSaasMapList.size());

		// 调用中台接口上报指标
		httpHandle(apiMapList, sdkMapList, h5MapList, paasSaasMapList);
	}


	/**
	 * 调用中台接口上报指标
	 * @param apiMapList	API 指标
	 * @param sdkMapList	SDK 指标
	 * @param h5MapList		H5 指标
	 * @param paasSaasMapList	Paas/Saas 指标
	 */
	private void httpHandle(List<Map<String, Map<String, Object>>> apiMapList,
							List<Map<String, Map<String, Object>>> sdkMapList,
							List<Map<String, Map<String, Object>>> h5MapList,
							List<Map<String, Map<String, Object>>> paasSaasMapList) throws Exception {
		// 获取相关配置参数
		long sTime = System.currentTimeMillis();
		String CREATE_INDEX_URL= "";
		String UPLOAD_INDEX_URL= "";
		try {
			CREATE_INDEX_URL= remoteParamService.getByKeyNoInner(ConfigKey.CREATE_INDEX_URL).getData();
			UPLOAD_INDEX_URL= remoteParamService.getByKeyNoInner(ConfigKey.UPLOAD_INDEX_URL).getData();
			log.info("实时指标-数据上报-远程调用-基础服务-获取公共参数配置-耗时: {} MS", System.currentTimeMillis() - sTime);
		} catch (Exception e) {
			log.error("实时指标-数据上报-远程调用-基础服务-获取公共参数配置-报错: {}" + e.getMessage());
			throw e;
		}

		if (StringUtils.isEmpty(CREATE_INDEX_URL) ||
				StringUtils.isEmpty(UPLOAD_INDEX_URL)) {

			log.warn("运营指标-数据上报-配置参数存在空值, 本轮上报结束, CREATE_INDEX_URL: {}, UPLOAD_INDEX_URL: {}", CREATE_INDEX_URL, UPLOAD_INDEX_URL);
			return;
		}

		try {
			// 1.向agent 创建指标(只需要创建一次即可)
			createIndexToTheAgent(CREATE_INDEX_URL, apiMapList, sdkMapList, h5MapList, paasSaasMapList);

			// 2.向agent 上报指标
			uploadIndexToTheAgent(UPLOAD_INDEX_URL, apiMapList, sdkMapList, h5MapList, paasSaasMapList);

		} catch (Exception e) {
			log.error("实时指标-数据上报-报错:{}", e.getMessage());
			throw new Exception(e);
		}
	}


	/**
	 * 向agent上报指标
	 * @param UPLOAD_INDEX_URL		上报指标的 agent 路径
	 * @param apiMapList			API 指标
	 * @param sdkMapList			SDK 指标
	 * @param h5MapList				H5 指标
	 * @param paasSaasMapList		Paas/Saas 指标
	 */
	private void uploadIndexToTheAgent(String UPLOAD_INDEX_URL,
									   List<Map<String, Map<String, Object>>> apiMapList,
									   List<Map<String, Map<String, Object>>> sdkMapList,
									   List<Map<String, Map<String, Object>>> h5MapList,
									   List<Map<String, Map<String, Object>>> paasSaasMapList) throws Exception {

		log.info("实时指标-数据上报-进入'上报'指标逻辑-开始");
		long startTime = System.currentTimeMillis();

		// 1.向 Agent 批量上报指标
		if (CollectionUtil.isNotEmpty(apiMapList)) {
			long sTime = System.currentTimeMillis();
			List<Map<String, Object>> metricList = new ArrayList<>();
			// 进行指标上报
			getUploadMetricList(metricList, apiMapList);
			HttpResultVo httpResultVo = HttpUtil.doPost(UPLOAD_INDEX_URL, JSONUtil.parse(metricList).toString());
			if (httpResultVo.getRespondCode() == 200) {
				log.info("实时指标-数据上报-请求上报API指标URL-成功-耗时：{} MS", System.currentTimeMillis() - sTime);
				Map<String, Object> userMap = (Map<String, Object>) JSONUtils.parse(httpResultVo.getRespondBody());
				if (CollectionUtil.isNotEmpty(userMap)) {
					List<Map<String, Object>> metricCreateDtoRespList = (List<Map<String, Object>>) userMap.get("metricCreateDtoResp");
					for (Map<String, Object> map : metricCreateDtoRespList) {
						String resultCode = (String) map.get("resultCode");
						// 指标上报成功时的结果码为1；上报指标含有不合格指标信息,每个指标上报的结果码为2
						if ("2".equals(resultCode)) {
							log.info("实时指标-数据上报-上报API指标-失败，resultCode：{}, resultDesc: {}", resultCode, map.get("resultDesc"));
						}
					}
				}
			} else {
				log.error("实时指标-数据上报-请求上报API指标URL-失败");
				throw new Exception("实时指标-数据上报-请求上报API指标URL-失败");
			}
		}

		if (CollectionUtil.isNotEmpty(sdkMapList)) {
			long sTime = System.currentTimeMillis();
			List<Map<String, Object>> metricList = new ArrayList<>();
			// 进行指标上报
			getUploadMetricList(metricList, sdkMapList);
			HttpResultVo httpResultVo = HttpUtil.doPost(UPLOAD_INDEX_URL, JSONUtil.parse(metricList).toString());
			if (httpResultVo.getRespondCode() == 200) {
				log.info("实时指标-数据上报-请求上报SDK指标URL-成功-耗时：{} MS", System.currentTimeMillis() - sTime);
				Map<String, Object> userMap = (Map<String, Object>) JSONUtils.parse(httpResultVo.getRespondBody());
				if (CollectionUtil.isNotEmpty(userMap)) {
					List<Map<String, Object>> metricCreateDtoRespList = (List<Map<String, Object>>) userMap.get("metricCreateDtoResp");
					for (Map<String, Object> map : metricCreateDtoRespList) {
						String resultCode = (String) map.get("resultCode");
						if ("2".equals(resultCode)) {
							log.info("实时指标-数据上报-上报SDK指标-失败，resultCode：{}, resultDesc: {}", resultCode, map.get("resultDesc"));
						}
					}
				}
			} else {
				log.error("实时指标-数据上报-请求上报SDK指标URL-失败");
				throw new Exception("实时指标-数据上报-请求上报SDK指标URL-失败");
			}
		}

		if (CollectionUtil.isNotEmpty(h5MapList)) {
			long sTime = System.currentTimeMillis();
			List<Map<String, Object>> metricList = new ArrayList<>();
			// 进行指标上报
			getUploadMetricList(metricList, h5MapList);
			HttpResultVo httpResultVo = HttpUtil.doPost(UPLOAD_INDEX_URL, JSONUtil.parse(metricList).toString());
			if (httpResultVo.getRespondCode() == 200) {
				log.info("实时指标-数据上报-请求上报H5指标URL-成功-耗时：{} MS", System.currentTimeMillis() - sTime);
				Map<String, Object> userMap = (Map<String, Object>) JSONUtils.parse(httpResultVo.getRespondBody());
				if (CollectionUtil.isNotEmpty(userMap)) {
					List<Map<String, Object>> metricCreateDtoRespList = (List<Map<String, Object>>) userMap.get("metricCreateDtoResp");
					for (Map<String, Object> map : metricCreateDtoRespList) {
						String resultCode = (String) map.get("resultCode");
						if ("2".equals(resultCode)) {
							log.info("实时指标-数据上报-上报API指标-失败，resultCode：{}, resultDesc: {}", resultCode, map.get("resultDesc"));
						}
					}
				}
			} else {
				log.error("实时指标-数据上报-请求上报API指标URL-失败");
				throw new Exception("实时指标-数据上报-请求上报API指标URL-失败");
			}
		}

		if (CollectionUtil.isNotEmpty(paasSaasMapList)) {
			long sTime = System.currentTimeMillis();
			List<Map<String, Object>> metricList = new ArrayList<>();
			// 进行指标上报
			getUploadMetricList(metricList, paasSaasMapList);
			HttpResultVo httpResultVo = HttpUtil.doPost(UPLOAD_INDEX_URL, JSONUtil.parse(metricList).toString());
			if (httpResultVo.getRespondCode() == 200) {
				log.info("实时指标-数据上报-请求上报PAAS_SAAS指标URL-成功-耗时：{} MS", System.currentTimeMillis() - sTime);
				Map<String, Object> userMap = (Map<String, Object>) JSONUtils.parse(httpResultVo.getRespondBody());
				if (CollectionUtil.isNotEmpty(userMap)) {
					List<Map<String, Object>> metricCreateDtoRespList = (List<Map<String, Object>>) userMap.get("metricCreateDtoResp");
					for (Map<String, Object> map : metricCreateDtoRespList) {
						String resultCode = (String) map.get("resultCode");
						if ("2".equals(resultCode)) {
							log.info("实时指标-数据上报-上报PAAS_SAAS指标-失败，resultCode：{}, resultDesc: {}", resultCode, map.get("resultDesc"));
						}
					}
				}
			} else {
				log.error("实时指标-数据上报-请求上报PAAS_SAAS指标URL-失败");
				throw new Exception("实时指标-数据上报-请求上报PAAS_SAAS指标URL-失败");
			}
		}

		log.info("实时指标-数据上报-进入'上报'指标逻辑-结束，耗时：{} MS", System.currentTimeMillis() - startTime);
	}


	/**
	 * 构建指标集合
	 */
	private void getUploadMetricList(List<Map<String, Object>> metricList, List<Map<String, Map<String, Object>>> list) {
		if (list.size() > 0) {
			Map<String, Map<String, Object>> apiMap = list.get(0);
			Map<String, Object> labelMap = apiMap.get("labelMap");    // 标签集
			Map<String, Object> indexMap = apiMap.get("indexMap");    // 指标集

			List<String> labelNames = new ArrayList<>();
			List<Object> labelValues = new ArrayList<>();

			for (Map.Entry<String, Object> entry : labelMap.entrySet()) {
				labelNames.add(entry.getKey());
				labelValues.add(entry.getValue() == null ? "" : entry.getValue());
				log.info("实时指标-数据上报-构建上传指标集合，标签名：{}， 标签值: {}", entry.getKey(), entry.getValue());
			}

			for (Map.Entry<String, Object> entry : indexMap.entrySet()) {
				Map<String, Object> indexInfoMap = new LinkedHashMap<>(); // 指标信息集合
				String key = entry.getKey();
				String value =  (entry.getValue() != null ? entry.getValue().toString() : "");
				indexInfoMap.put("name", key);
				indexInfoMap.put("labelNames", labelNames);
				indexInfoMap.put("labels", labelValues);
				indexInfoMap.put("value", value);
				metricList.add(indexInfoMap);
			}
		}
	}


	/**
	 * 向agent创建指标
	 * @param CREATE_INDEX_URL		上报指标的 agent 路径
	 * @param apiMapList			API 指标
	 * @param sdkMapList			SDK 指标
	 * @param h5MapList				H5 指标
	 * @param paasSaasMapList		Paas/Saas 指标
	 */
	private void createIndexToTheAgent(String CREATE_INDEX_URL,
									   List<Map<String, Map<String, Object>>> apiMapList,
									   List<Map<String, Map<String, Object>>> sdkMapList,
									   List<Map<String, Map<String, Object>>> h5MapList,
									   List<Map<String, Map<String, Object>>> paasSaasMapList) throws Exception {

		log.info("实时指标-数据上报-进入'创建'指标逻辑-开始");
		long startTime = System.currentTimeMillis();

		// 1.向 Agent 批量创建指标
		if (!API_INDEX_CREATE_FLAG && CollectionUtil.isNotEmpty(apiMapList)) {
			boolean flag = true;
			long sTime = System.currentTimeMillis();
			List<Map<String, Object>> metricList = new ArrayList<>();
			// 进行指标创建
			getCreateMetricList(metricList, apiMapList, IndexTypeEnum.COUNTER.getCode());
			HttpResultVo httpResultVo = HttpUtil.doPost(CREATE_INDEX_URL, JSONUtil.parse(metricList).toString());
			if (httpResultVo.getRespondCode() == 200) {
				log.info("实时指标-数据上报-请求创建API指标URL-成功-耗时：{} MS", System.currentTimeMillis() - sTime);
				Map<String, Object> userMap = (Map<String, Object>) JSONUtils.parse(httpResultVo.getRespondBody());
				if (CollectionUtil.isNotEmpty(userMap)) {
					List<Map<String, Object>> metricCreateDtoRespList = (List<Map<String, Object>>) userMap.get("metricCreateDtoResp");
					for (Map<String, Object> map : metricCreateDtoRespList) {
						String resultCode = (String) map.get("resultCode");
						// 指标创建成功时的结果码为1；上报指标含有不合格指标信息,每个指标创建的结果码为2
						if ("2".equals(resultCode)) {
							flag = false;
							log.info("实时指标-数据上报-创建API指标-失败，resultCode：{}, resultDesc: {}", resultCode, map.get("resultDesc"));
						}
					}
				}
			} else {
				log.error("实时指标-数据上报-请求创建API指标URL-失败");
				throw new Exception("实时指标-数据上报-请求创建API指标URL-失败");
			}
			API_INDEX_CREATE_FLAG = flag;
		}

		if (!SDK_INDEX_CREATE_FLAG && CollectionUtil.isNotEmpty(sdkMapList)) {
			boolean flag = true;
			long sTime = System.currentTimeMillis();
			List<Map<String, Object>> metricList = new ArrayList<>();
			// 进行指标创建
			getCreateMetricList(metricList, sdkMapList, IndexTypeEnum.COUNTER.getCode());
			HttpResultVo httpResultVo = HttpUtil.doPost(CREATE_INDEX_URL, JSONUtil.parse(metricList).toString());
			if (httpResultVo.getRespondCode() == 200) {
				log.info("实时指标-数据上报-请求创建SDK指标URL-成功-耗时：{} MS", System.currentTimeMillis() - sTime);
				Map<String, Object> userMap = (Map<String, Object>) JSONUtils.parse(httpResultVo.getRespondBody());
				if (CollectionUtil.isNotEmpty(userMap)) {
					List<Map<String, Object>> metricCreateDtoRespList = (List<Map<String, Object>>) userMap.get("metricCreateDtoResp");
					for (Map<String, Object> map : metricCreateDtoRespList) {
						String resultCode = (String) map.get("resultCode");
						if ("2".equals(resultCode)) {
							flag = false;
							log.info("实时指标-数据上报-创建SDK指标-失败，resultCode：{}, resultDesc: {}", resultCode, map.get("resultDesc"));
						}
					}
				}
			} else {
				log.error("实时指标-数据上报-请求创建SDK指标URL-失败");
				throw new Exception("实时指标-数据上报-请求创建SDK指标URL-失败");
			}
			SDK_INDEX_CREATE_FLAG = flag;
		}

		if (!H5_INDEX_CREATE_FLAG && CollectionUtil.isNotEmpty(h5MapList)) {
			boolean flag = true;
			long sTime = System.currentTimeMillis();
			List<Map<String, Object>> metricList = new ArrayList<>();
			// 进行指标创建
			getCreateMetricList(metricList, h5MapList, IndexTypeEnum.COUNTER.getCode());
			HttpResultVo httpResultVo = HttpUtil.doPost(CREATE_INDEX_URL, JSONUtil.parse(metricList).toString());
			if (httpResultVo.getRespondCode() == 200) {
				log.info("实时指标-数据上报-请求创建H5指标URL-成功-耗时：{} MS", System.currentTimeMillis() - sTime);
				Map<String, Object> userMap = (Map<String, Object>) JSONUtils.parse(httpResultVo.getRespondBody());
				if (CollectionUtil.isNotEmpty(userMap)) {
					List<Map<String, Object>> metricCreateDtoRespList = (List<Map<String, Object>>) userMap.get("metricCreateDtoResp");
					for (Map<String, Object> map : metricCreateDtoRespList) {
						String resultCode = (String) map.get("resultCode");
						if ("2".equals(resultCode)) {
							flag = false;
							log.info("实时指标-数据上报-创建API指标-失败，resultCode：{}, resultDesc: {}", resultCode, map.get("resultDesc"));
						}
					}
				}
			} else {
				log.error("实时指标-数据上报-请求创建API指标URL-失败");
				throw new Exception("实时指标-数据上报-请求创建API指标URL-失败");
			}
			H5_INDEX_CREATE_FLAG = flag;
		}

		if (!PAAS_SAAS_INDEX_CREATE_FLAG && CollectionUtil.isNotEmpty(paasSaasMapList)) {
			boolean flag = true;
			long sTime = System.currentTimeMillis();
			List<Map<String, Object>> metricList = new ArrayList<>();
			// 进行指标创建
			getCreateMetricList(metricList, paasSaasMapList, IndexTypeEnum.COUNTER.getCode());
			HttpResultVo httpResultVo = HttpUtil.doPost(CREATE_INDEX_URL, JSONUtil.parse(metricList).toString());
			if (httpResultVo.getRespondCode() == 200) {
				log.info("实时指标-数据上报-请求创建PAAS_SAAS指标URL-成功-耗时：{} MS", System.currentTimeMillis() - sTime);
				Map<String, Object> userMap = (Map<String, Object>) JSONUtils.parse(httpResultVo.getRespondBody());
				if (CollectionUtil.isNotEmpty(userMap)) {
					List<Map<String, Object>> metricCreateDtoRespList = (List<Map<String, Object>>) userMap.get("metricCreateDtoResp");
					for (Map<String, Object> map : metricCreateDtoRespList) {
						String resultCode = (String) map.get("resultCode");
						if ("2".equals(resultCode)) {
							flag = false;
							log.info("实时指标-数据上报-创建PAAS_SAAS指标-失败，resultCode：{}, resultDesc: {}", resultCode, map.get("resultDesc"));
						}
					}
				}
			} else {
				log.error("实时指标-数据上报-请求创建PAAS_SAAS指标URL-失败");
				throw new Exception("实时指标-数据上报-请求创建PAAS_SAAS指标URL-失败");
			}
			PAAS_SAAS_INDEX_CREATE_FLAG = flag;
		}

		log.info("实时指标-数据上报-进入'创建'指标逻辑-结束，耗时：{} MS", System.currentTimeMillis() - startTime);
	}


	/**
	 * 构建指标集合
	 */
	private void getCreateMetricList(List<Map<String, Object>> metricList,
							   List<Map<String, Map<String, Object>>> list,
							   String indexType) {
		if (list.size() > 0) {
			Map<String, Map<String, Object>> apiMap = list.get(0);
			Map<String, Object> labelMap = apiMap.get("labelMap");   // 标签集
			Map<String, Object> indexMap = apiMap.get("indexMap");    // 指标集

			List<String> labelNames = new ArrayList<>();
			List<Object> labelValues = new ArrayList<>();

			for (Map.Entry<String, Object> entry : labelMap.entrySet()) {
				labelNames.add(entry.getKey());
				labelValues.add(entry.getValue() == null ? "" : entry.getValue());
				log.info("实时指标-数据上报-构建上传指标集合，标签名：{}， 标签值: {}", entry.getKey(), entry.getValue());
			}

			for (Map.Entry<String, Object> entry : indexMap.entrySet()) {
				Map<String, Object> indexInfoMap = new LinkedHashMap<>(); // 指标信息集合
				String key = entry.getKey();
				String value =  (entry.getValue() != null ? entry.getValue().toString() : "");
				indexInfoMap.put("name", key);
				indexInfoMap.put("help", key);
				indexInfoMap.put("labelNames", labelNames);
				indexInfoMap.put("labels", labelValues);
				indexInfoMap.put("value", value);
				indexInfoMap.put("type", indexType);
				metricList.add(indexInfoMap);
			}
		}

	}



	/**
	 * 运营指标 数据文件和校验文件 上报
	 * @param param	请求参数
	 */
	@Override
	public void operationalFileReporting(IndicatorReportingParam param) throws Exception {
		// 初始化 SFTP 相关配置
		String SFTP_IP = null, SFTP_PORT = null, SFTP_USER = null, SFTP_PW = null, SFTP_UPLOAD_PATH = null;
		long sTime = System.currentTimeMillis();
		try {
			SFTP_IP = remoteParamService.getByKeyNoInner(ConfigKey.SFTP_IP).getData();
			SFTP_PORT = remoteParamService.getByKeyNoInner(ConfigKey.SFTP_PORT).getData();
			SFTP_USER = remoteParamService.getByKeyNoInner(ConfigKey.SFTP_USER).getData();
			SFTP_PW = remoteParamService.getByKeyNoInner(ConfigKey.SFTP_PW).getData();
			SFTP_UPLOAD_PATH = remoteParamService.getByKeyNoInner(ConfigKey.SFTP_UPLOAD_PATH).getData();
			log.info("运营指标-数据上报-远程调用-基础服务-获取公共参数配置-耗时: {} MS", System.currentTimeMillis() - sTime);
		} catch (Exception e) {
			log.error("运营指标-数据上报-远程调用-基础服务-获取公共参数配置-报错: {}" + e.getMessage());
			throw e;
		}

		if (StringUtils.isEmpty(SFTP_IP) ||
				StringUtils.isEmpty(SFTP_PORT) ||
				StringUtils.isEmpty(SFTP_USER) ||
				StringUtils.isEmpty(SFTP_PW) ||
				StringUtils.isEmpty(SFTP_UPLOAD_PATH) ) {

			log.warn("运营指标-数据上报-FTP配置参数存在空值,本轮上报结束, FTP_IP: {}, FTP_PORT: {}, FTP_USER: {}, FTP_PW: {}, FTP_UPLOAD_PATH: {}",
					SFTP_IP, SFTP_PORT, SFTP_USER, SFTP_PW, SFTP_UPLOAD_PATH);
			return;
		}

		List<String> fileReportingInfoList = new ArrayList<>();

		// 获取运营指标数据
		param.setPageNum(1);
		param.setPageSize(-1);
		List<Object> list = new ArrayList<>();
		R<OperationalIndicatorResultVo> r = queryOperationalIndicators(param);
		if (r != null && r.getData() != null && r.getData().getPageDataInfo() != null) {
			list = (List<Object>) r.getData().getPageDataInfo().getData();
		}

		if (list.size() <= 0) {
			log.warn("运营指标-数据上报-查询不到数据, list.size(): {}, 本轮上报结束", list.size());
			return;
		}

		// 解析并组装'数据'文件数据   key: 日期_单位_能力_服务  value:对应的数据
		Map<String, List<String>> map = assemblyData(list);
		sTime = System.currentTimeMillis();
		for (Map.Entry<String, List<String>> entry : map.entrySet()) {
			// 生成数据文件
			String key = entry.getKey();
			String[] keyArr = key.split("_");
			String cycleTime = keyArr[0];
			String orderCode = keyArr[1];
			String abilityCode = keyArr[2];
			String serviceCode = keyArr[3];

			List<String> value = entry.getValue();
			String dataFileName = "D" + "_" + orderCode + "_" + "F30004" + "_" + abilityCode + "_" + serviceCode + "_" + cycleTime + "_" + "00" + ".txt";
			String dataFileInfo = SFTP_DOWN_PATH + dataFileName;
			try {
				TextFileGenerator.generateTextFile(dataFileInfo, value);
				log.info("运营指标-数据上报-生成数据文件: {}", dataFileInfo);
			} catch (Exception e) {
				e.printStackTrace();
				log.error("运营指标-数据上报-生成数据文件:{} -报错:{}", dataFileInfo, e.getMessage());
				throw e;
			}

			// 生成校验文件
			File file = new File(dataFileInfo);
			String verifyFileName = "D" + "_" + orderCode + "_" + "F30004" + "_" + abilityCode + "_" + serviceCode + "_" + cycleTime + "_" + "00" + ".chk";
			String dataFileCreateTime = DateUtil.format(new Date(), "yyyyMMddHHmmss");		// 数据文件生成时间
			long dataFileSize = file.length();			// 数据文件体积大小
			int dataSize = list.size();					// 数据文件条数
			String specificationVersion = "V2.0.0";		// 规范版本
			String sb = dataFileName + "€€" +
					verifyFileName + "€€" +
					dataFileCreateTime + "€€" +
					dataFileSize + "€€" +
					dataSize + "€€" +
					specificationVersion;

			String verifyFileInfo = SFTP_DOWN_PATH + File.separator + verifyFileName;
			try {
			TextFileGenerator.generateTextFile(verifyFileInfo, Collections.singletonList(sb));
			log.info("运营指标-数据上报-生成校验文件: {}", verifyFileInfo);
			} catch (Exception e) {
				e.printStackTrace();
				log.error("运营指标-数据上报-生成数据文件:{} -报错:{}", dataFileInfo, e.getMessage());
				throw e;
			}
			fileReportingInfoList.add(dataFileInfo);
			fileReportingInfoList.add(verifyFileInfo);
		}

		// 发送文件到SFTP
		log.info("运营指标-数据上报-文件生成结束耗时：{}MS,文件数量：{}, 开始发送到SFTP", System.currentTimeMillis() - sTime, fileReportingInfoList.size());
		sTime = System.currentTimeMillis();
		if (fileReportingInfoList.size() > 0) {
			sftpUtils.uploadFileUsingSshj(fileReportingInfoList,
					SFTP_IP,
					SFTP_PORT,
					SFTP_USER,
					SFTP_PW,
					SFTP_UPLOAD_PATH);
		}
		log.info("运营指标-数据上报-上报文件-结束-文件数量: {}, 耗时: {}", fileReportingInfoList.size(), System.currentTimeMillis() - sTime);
	}


	/**
	 * 解析并组装'数据'文件数据
	 * @param list 带解析数据
	 * @return 组装后的结果数据
	 */
	private Map<String, List<String>> assemblyData(List<Object> list) throws Exception {
		// key: 日期_单位_能力_服务  value:对应的数据
		Map<String, List<String>> resultMap = new LinkedHashMap<>();
		try {
			if (CollectionUtil.isNotEmpty(list)) {
				for (int i = 0; i < list.size(); i++) {
					StringBuilder sb = new StringBuilder();
					// 获取基本的字段值
					LinkedHashMap<String, Object> map = (LinkedHashMap<String, Object>) list.get(i);
					String cycleTime = (String) map.get("cycleTime");            // 日期
					String unifiedSceneEncoding = "";                            // 统一场景编码
					String abilityCode = (String) map.get("abilityCode");        // 统一能力编码
					String abilityName = (String) map.get("abilityName");        // 统一能力编码
					String serviceCode = (String) map.get("serviceCode");        // 统一服务编码
					String serviceName = (String) map.get("serviceName");        // 统一服务编码
					String orgCode = (String) map.get("orgCode");                // 单位编码
					String orgName = (String) map.get("orgName");                // 单位名称
					String userOrgCode = (String) map.get("userOrgCode");        // 能力使用方编码
					String userOrgName = (String) map.get("userOrgName");        // 能力使用方名称
					String appCode = (String) map.get("appCode");                // 能力使用方应用编码
					String appName = (String) map.get("appName");                // 能力使用方应用名称
					String departmentCode = (String) map.get("departmentCode"); // 能力使用方服务机构编码
					String departmentName = (String) map.get("departmentName"); // 能力使用方服务机构名称
					String orderCode = (String) map.get("orderCode");            // 智慧中台门户订单号
					String suborderCode = (String) map.get("suborderCode");    // 智慧中台门户子订单号
					String requestMapJSON = "";                                    // 调用量
					String requestFailMapJSON = "";                                // 调用失败量及失败原因

					// 获取 请求量 字段里面的 对应各个 量纲 的值
					Map<String, Object> reqCountMap = (LinkedHashMap<String, Object>) map.get("reqCountMap");
					Map<String, Object> requestMap = new LinkedHashMap<>();
					Map<String, Object> request_ZLG_Map = new LinkedHashMap<>();
					List<Map<String, Object>> request_FLG_List = new ArrayList<>();        // 请求量-> 副量纲
					int requestIndex = 1;
					for (Map.Entry<String, Object> entry : reqCountMap.entrySet()) {
						String key = entry.getKey().split("_")[0];
						Object value = entry.getValue();

						if (requestIndex == 1) {
							// 回填 主量纲
							request_ZLG_Map.put(key, value);
							requestMap.put(ZLG, request_ZLG_Map);
							requestIndex++;
						} else {
							// 回填 副量纲
							Map<String, Object> FLG_childMap = new LinkedHashMap<>();
							FLG_childMap.put(key, value);
							request_FLG_List.add(FLG_childMap);
						}
					}
					// 判断是否存在 '副量纲'
					if (request_FLG_List.size() > 0) {
						requestMap.put(FLG, request_FLG_List);
					}
					requestMapJSON = JSONUtil.parse(requestMap).toString();


					// 获取 失败请求量 字段里面的 对应各个 量纲 的值
					Map<String, Map<String, Object>> reqFailCountMap = (LinkedHashMap<String, Map<String, Object>>) map.get("reqFailCountMap");
					Map<String, Object> reqFailSelfReasonsMap = reqFailCountMap.get("reqFailSelfReasons");
					Map<String, Object> reqFailOtherReasonsMap = reqFailCountMap.get("reqFailOtherReasonsMap");

					Map<String, Object> reqResultMapFail = new LinkedHashMap<>();

					// 回填 自身失败原因 和 非自身失败原因 的 主量纲 数据 reqFailSelfReasonsMap 和 reqFailOtherReasonsMap 各自第一个元素则是 主量纲
					Map<String, Object> ZLG_FailMap = new LinkedHashMap<>();
					Map<String, Object> ZLG_ZSYY_FailMap = new LinkedHashMap<>();
					Map<String, Object> ZLG_FZSYY_FailMap = new LinkedHashMap<>();
					for (Map.Entry<String, Object> entry : reqFailSelfReasonsMap.entrySet()) {
						String key = entry.getKey().split("_")[0];
						Object value = entry.getValue();
						ZLG_ZSYY_FailMap.put(key, value);
						break;
					}
					for (Map.Entry<String, Object> entry : reqFailOtherReasonsMap.entrySet()) {
						String key = entry.getKey().split("_")[0];
						Object value = entry.getValue();
						ZLG_FZSYY_FailMap.put(key, value);
						break;
					}
					ZLG_FailMap.put(ZSYY, ZLG_ZSYY_FailMap);
					ZLG_FailMap.put(FZSYY, ZLG_FZSYY_FailMap);
					reqResultMapFail.put(ZLG, ZLG_FailMap);

					// 回填 自身失败原因 和 非自身失败原因 的 副量纲 数据 reqFailSelfReasonsMap 和 reqFailOtherReasonsMap 各自第二个及后面的元素则是 副量纲
					if (reqFailSelfReasonsMap.size() > 1 && reqFailOtherReasonsMap.size() > 1) {
						List<Map<String, Object>> FLG_FailList = new ArrayList<>();
						Map<String, Object> FLG_ZSYY_FailMap = new LinkedHashMap<>();
						Map<String, Object> FLG_ZSYY_Child_FailMap = new LinkedHashMap<>();
						int requestFailSelfIndex = 1;
						for (Map.Entry<String, Object> entry : reqFailSelfReasonsMap.entrySet()) {
							String key = entry.getKey().split("_")[0];
							Object value = entry.getValue();
							if (requestFailSelfIndex > 1) {
								FLG_ZSYY_Child_FailMap.put(key, value);
							}
							requestFailSelfIndex++;
						}
						FLG_ZSYY_FailMap.put(ZSYY, FLG_ZSYY_Child_FailMap);
						FLG_FailList.add(FLG_ZSYY_FailMap);

						Map<String, Object> FLG_FZSYY_FailMap = new LinkedHashMap<>();
						Map<String, Object> FLG_FZSYY_Child_FailMap = new LinkedHashMap<>();
						int requestFailOtherIndex = 1;
						for (Map.Entry<String, Object> entry : reqFailOtherReasonsMap.entrySet()) {
							String key = entry.getKey().split("_")[0];
							Object value = entry.getValue();
							if (requestFailOtherIndex > 1) {
								FLG_FZSYY_Child_FailMap.put(key, value);
							}
							requestFailOtherIndex++;
						}
						FLG_FZSYY_FailMap.put(FZSYY, FLG_FZSYY_Child_FailMap);
						FLG_FailList.add(FLG_FZSYY_FailMap);

						reqResultMapFail.put(FLG, FLG_FailList);
					}
					requestFailMapJSON = JSONUtil.parse(reqResultMapFail).toString();

					sb.append(i + 1).append("€€")
							.append(cycleTime).append("€€")
							.append(unifiedSceneEncoding).append("€€")
							.append(abilityCode).append("€€")
							.append(serviceCode).append("€€")
							.append(userOrgName).append("€€")
							.append(userOrgCode).append("€€")
							.append(appName).append("€€")
							.append(appCode).append("€€")
							.append(departmentName).append("€€")
							.append(departmentCode).append("€€")
							.append(orderCode).append("€€")
							.append(suborderCode).append("€€")
							.append(requestMapJSON).append("€€")
							.append(requestFailMapJSON);

					String key = cycleTime + "_" + orgCode + "_" + abilityCode + "_" + serviceCode;

					resultMap.computeIfAbsent(key, k -> new ArrayList<>());
					List<String> childList = resultMap.get(key);
					childList.add(sb.toString());
				}
			}
		} catch (Exception e) {
			log.error("运营指标-数据上报-解析并组装'数据'文件数据-报错: {}", e.getMessage());
			throw e;
		}

		return resultMap;
	}


	/**
	 * 手动对数据进行分页处理
	 * @param params 请求参数
	 * @param resultList 分页目标
	 * @return 结果集
	 */
	public List<?> getResultListByPage(IndicatorReportingParam params, List<?> resultList) {
		long pageSize = params.getPageSize(); // 每页条数
		long pageNum = params.getPageNum(); // 页码
		long pageStart = (pageNum - 1) * pageSize;
		long pageEnd = pageStart + pageSize;
		List<Object> result = new ArrayList<>();
		if (CollectionUtils.isEmpty(resultList)) { return result; }

		long detailIdListSize = resultList.size();
		if (detailIdListSize < pageEnd) { pageEnd = detailIdListSize; }

		for (long i = pageStart; i < pageEnd; i++) {
			result.add(resultList.get((int) i));
		}
		return result;
	}


	/**
	 * 获取 主/副 量纲数据
	 * @param param	请求参数
	 * @param majorDimension	量纲字段
	 * @return 结果集
	 */
	private List<OperationalIndicatorVo> getDimension(IndicatorReportingParam param, String majorDimension) {

		List<OperationalIndicatorVo> majorDimensionDataVoList = new ArrayList<>();

		if (MajorDimensionEnum.XTYWL.getCode().equalsIgnoreCase(majorDimension)) {
			majorDimensionDataVoList = reportingMapper.selectApiSdk(param);

		} else if (MajorDimensionEnum.YHSYL.getCode().equalsIgnoreCase(majorDimension)) {
			majorDimensionDataVoList = reportingMapper.selectSaasPaasSdk(param);
		}

		return majorDimensionDataVoList;
	}



}
